package com.edge.pbx.view.xover;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.hardware.SensorManager;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;


import com.edge.pbxdsp.R;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

public class XoverSlopeWheelView extends View {

    public static final String TAG = "MyScrollView";

    private int mItemCount = 3;
    Paint mTextPaint, zPaint;
    //数据源
    List<Drawable> mNumDrawables;

    //字的大小
    int textSize = 50;
    //item height
    int mItemHeight = 80;

    //偏差
    float offSet = 0;

    //view的宽高
    int width, height;
    //总高度
    int sumHeight;

    float centerY;

    float mCurrentTouchY;
//    float move;
    private List<Integer> mShowIndex;
    private VelocityTracker mVelocityTracker;

    /**
     * 自动回滚到中间的速度
     */
    public static final float SPEED = 5;
    //甩手和归为
    private Timer timer;
    private MyTimerTask mTask;

    //归位，为了一定选中某个item
    private Timer flingtimer;
    private MyTimerTask flingmTask;
    Handler updateHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            if (Math.abs(surplus) < SPEED) {
                surplus = 0;
                if (mTask != null) {
                    mTask.cancel();
                    mTask = null;
                }
            } else if (surplus != 0) {
                offSet = surplus / Math.abs(surplus) * SPEED + offSet;
                surplus = (int) (surplus - surplus / Math.abs(surplus) * SPEED);
                invalidate();

            }


        }

    };

    //fling实现
    Handler flingHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (Math.abs(yVelocity) < mMinimumFlingVelocity) {
                yVelocity = 0;
                if (flingmTask != null) {
                    flingmTask.cancel();
                    flingmTask = null;
                }
                guiwei();

            } else if (yVelocity != 0) {
                offSet = (float) (offSet + yVelocity * 0.01);
                double d = distance - Math.abs(yVelocity) * 0.01;
                yVelocity = getVelocityByDistance(distance) * yVelocity / Math.abs(yVelocity);
                distance = d;
                invalidate();
            }

        }
    };

    public XoverSlopeWheelView(Context context) {
        super(context);
        init();
    }

    public XoverSlopeWheelView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public void init() {


        mTextPaint = new Paint();
        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setTextAlign(Paint.Align.CENTER);
        mTextPaint.setColor(Color.GREEN);
        mTextPaint.setTextSize(textSize);

        zPaint = new Paint();
        zPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        zPaint.setStyle(Paint.Style.FILL);
        zPaint.setTextAlign(Paint.Align.CENTER);
        zPaint.setColor(0xFF1a1a1a);
        zPaint.setTextSize(textSize);

        mNumDrawables = new ArrayList<>();

        mNumDrawables.add(getResources().getDrawable(R.drawable.pbx_xover_icon_slop_6));
        mNumDrawables.add(getResources().getDrawable(R.drawable.pbx_xover_icon_slop_12));
        mNumDrawables.add(getResources().getDrawable(R.drawable.pbx_xover_icon_slop_24));
        mNumDrawables.add(getResources().getDrawable(R.drawable.pbx_xover_icon_slop_36));
        mNumDrawables.add(getResources().getDrawable(R.drawable.pbx_xover_icon_slop_48));

        mShowIndex = new ArrayList<>();
        for (int i = 0; i < mNumDrawables.size(); i++) {
            mShowIndex.add(i);
        }
        sumHeight = mItemHeight * mNumDrawables.size();
//        sumHeight = interval * (dataList.size() + 1) + textSize * dataList.size();

//        centerY = (float) (interval + textSize * 1.5);
        centerY = mItemHeight * 1.5f;

        timer = new Timer();
        flingtimer = new Timer();

        final ViewConfiguration viewConfiguration = ViewConfiguration.get(getContext());
        mMinimumFlingVelocity = viewConfiguration.getScaledMinimumFlingVelocity();
        mMaximumFlingVelocity = viewConfiguration.getScaledMaximumFlingVelocity();
        minFLingDistance = getSplineFlingDistance(mMinimumFlingVelocity);

/*
        List<String> dataList = new ArrayList<>();
        for (int i = 0; i < 30; i++) {
            dataList.add("" + i);
        }
        setDataList(dataList);*/
    }

    double minFLingDistance;
    int frameOffset = 1;
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width = w;
        frameOffset = (int) (width * 0.08f);
        height = h;
        int itemHeigh = height/mItemCount;
        if (mItemHeight != itemHeigh){
            mItemHeight = itemHeigh;
            sumHeight = mItemHeight * mShowIndex.size();
            centerY = mItemHeight * 1.5f;
        }
    }

    public void setSelectIndex(int index){

        Log.d(TAG,"setSelectItem:"+ index);
        offSet = (1 - index )*mItemHeight;
        postInvalidate();
    }

    public int getSelectIndex() {
        return mSelectIndex;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mNumDrawables == null || mNumDrawables.size() == 0) {
            return;
        }
        float r = mItemHeight*0.1f;
        canvas.drawRoundRect(frameOffset,mItemHeight,width- frameOffset,mItemHeight+mItemHeight,r,r,zPaint);

      //  Log.d(TAG, "offset:" + offSet);

        //滑动下限

        if (offSet <= -sumHeight + mItemHeight * 2) {
            offSet = -sumHeight + mItemHeight * 2;
        }

        //滑动上限
        if (offSet > mItemHeight) {
            offSet = mItemHeight;
        }

        int index = (int)((Math.abs(offSet-mItemHeight)+ mItemHeight/2)/mItemHeight);
     //   Log.d(TAG, "---offset:" + offSet +"  "+ index);

//        float start = offSet;
        Drawable drawable;
        int x = 0, t = 0;
        for (int i = Math.max(0, index-2), end = Math.min(index+3, mShowIndex.size()); i < end; i++){
            drawable = mNumDrawables.get(mShowIndex.get(i));
            x = (width - mItemHeight)/2;
            t = (int) (offSet+ mItemHeight*i);
            drawable.setBounds(x, t, x + mItemHeight, t + mItemHeight);
            drawable.draw(canvas);
            // 获取到的是实际文字宽度
//            canvas.drawText(text, width/2, offSet+ mItemHeight*i +  + (mItemHeight + rect.height()) / 2, mTextPaint);
//            start = start + mItemHeight;
        }
//        for (String s : dataList) {
//
//            Rect rect = new Rect();
//            mTextPaint.getTextBounds(s, 0, s.length(), rect);
//            // 获取到的是实际文字宽度
//            canvas.drawText(s, width/2, start + (mItemHeight + rect.height()) / 2, mTextPaint);
//            start = start + mItemHeight;
//
//        }


    }

    int surplus;
    private int mMaximumFlingVelocity;
    private int mMinimumFlingVelocity;

    int yVelocity;

    int duration;
    double distance;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!isEnabled())return false;
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                mCurrentTouchY = event.getY();
                initOrResetVelocityTracker();
                break;
            case MotionEvent.ACTION_MOVE:
                float move = event.getY() - mCurrentTouchY;
                mCurrentTouchY = event.getY();
                offSet = offSet + move;
                invalidate();

                break;
            case MotionEvent.ACTION_UP:

                final VelocityTracker velocityTracker = mVelocityTracker;
                velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
                if (Math.abs(velocityTracker.getYVelocity()) > mMinimumFlingVelocity) {
                    yVelocity = (int) velocityTracker.getYVelocity();
                    duration = getSplineFlingDuration(yVelocity);
                    distance = getSplineFlingDistance(yVelocity);

                    Log.v(TAG, "初速度：" + yVelocity + "移动距离：" + distance + "移动时间：" + duration);
                    if (flingmTask != null) {
                        flingmTask.cancel();
                        flingmTask = null;
                    }
                    flingmTask = new MyTimerTask(flingHandler);
                    flingtimer.schedule(flingmTask, 0, 10);

                } else {
                    guiwei();
                }

                invalidate();

                break;
        }

        if (mVelocityTracker != null) {
            mVelocityTracker.addMovement(event);
        }
        return true;
    }


    class MyTimerTask extends TimerTask {
        Handler handler;

        public MyTimerTask(Handler handler) {
            this.handler = handler;
        }

        @Override
        public void run() {
            handler.sendMessage(handler.obtainMessage());
        }

    }


    private void initOrResetVelocityTracker() {
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        } else {
            mVelocityTracker.clear();
        }
    }


    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        final float ppi = getContext().getResources().getDisplayMetrics().density * 160.0f;
        mPhysicalCoeff = SensorManager.GRAVITY_EARTH // g (m/s^2)
                * 39.37f // inch/meter
                * ppi
                * 0.84f; // look and feel tuning
    }

    private static final float INFLEXION = 0.35f; // Tension lines cross at (INFLEXION, 1)

    // A context-specific coefficient adjusted to physical values.
    private float mPhysicalCoeff;


    private static float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9));

    // Fling friction
    private float mFlingFriction = ViewConfiguration.getScrollFriction();


    //获取滑动的时间
    private int getSplineFlingDuration(int velocit) {
        final double l = getSplineDeceleration(velocit);
        final double decelMinusOne = DECELERATION_RATE - 1.0;
        return (int) (1000.0 * Math.exp(l / decelMinusOne));
    }

    private double getSplineDeceleration(float velocity) {
        return Math.log(INFLEXION * Math.abs(velocity) / (mFlingFriction * mPhysicalCoeff));
    }


    //通过初始速度获取最终滑动距离
    private double getSplineFlingDistance(int velocity) {
        final double l = getSplineDeceleration(velocity);
        final double decelMinusOne = DECELERATION_RATE - 1.0;
        return mFlingFriction * mPhysicalCoeff * Math.exp(DECELERATION_RATE / decelMinusOne * l);
    }

    //通过需要滑动的距离获取初始速度
    public int getVelocityByDistance(double distance) {
        final double l = getSplineDecelerationByDistance(distance);
        int velocity = (int) (Math.exp(l) * mFlingFriction * mPhysicalCoeff / INFLEXION);
        return Math.abs(velocity);
    }

    private double getSplineDecelerationByDistance(double distance) {
        final double decelMinusOne = DECELERATION_RATE - 1.0;
        return decelMinusOne * (Math.log(distance / (mFlingFriction * mPhysicalCoeff))) / DECELERATION_RATE;
    }

    int mSelectIndex;

    public void guiwei() {
        if (offSet < 0) {
            surplus = (int) (-offSet) % (int) (mItemHeight);
            if (surplus < (mItemHeight) / 2) {

            } else {
                surplus = -(mItemHeight - surplus);
            }
        } else {
            surplus = (int) (offSet) % (int) (mItemHeight);
            if (surplus < (mItemHeight) / 2) {

                surplus = -surplus;
            } else {
                surplus = mItemHeight - surplus;
            }
        }

        mSelectIndex = -(int) ((surplus + offSet) / (mItemHeight)) + 1;

        Log.v(TAG, "currentItem: " + mSelectIndex);
        if (selectItemListener != null) {
            selectItemListener.selectItem(this,mSelectIndex);
        }


        if (mTask != null) {
            mTask.cancel();
            mTask = null;
        }
        mTask = new MyTimerTask(updateHandler);
        timer.schedule(mTask, 0, 10);
    }

    public interface SelectItemListener {
        void selectItem(XoverSlopeWheelView view, int index);
    }

    private SelectItemListener selectItemListener;

    public void setSelectItemListener(SelectItemListener selectItemListener) {
        this.selectItemListener = selectItemListener;
    }
    public void setShowIndex(int[] indexs){
        mShowIndex.clear();
        if (indexs == null)return;
        for (int index : indexs) {
            mShowIndex.add(index);
        }
        sumHeight = mItemHeight * mShowIndex.size();
        postInvalidate();
    }

}
